#include "tile.h"

/// Name:		 Default Constructor
/// Description: Initualizes a Tile correctly  with default settings
/// Param(s):	 (void)
/// Return(s):	 (void) returns nothing
Tile::Tile()
{
	this->imageName = "";
	this->collision = false;
	this->number = NULL;
	this->bin = "0000000000000000";
	this->hex = BinaryConverter( this->bin );
	this->rect.Top = 0.0f;
	this->rect.Bottom = 0.0f;
	this->rect.Left = 0.0f;
	this->rect.Right = 0.0f;
}

/// Name:		 Copy Constructor
/// Description: Initualizes a Tile correctly
/// Param(s):	 (Tile&) a reference to a Tile object
/// Return(s):	 (void) returns nothing
Tile::Tile(Tile &tile)
{
	this->collision = tile.collision;
	this->imageName = tile.imageName;
	this->number = tile.number;
	this->bin = tile.bin;
	this->hex = BinaryConverter( tile.hex );
	this->rect = tile.rect;
	this->image = tile.image;
	this->sprite.SetImage( tile.image );
}

/// Name:		 Assignment Operator
/// Description: assigneds a tile from the right hand side to the
///				 left hand side
/// Param(s):	 (Tile&) a reference to a tile object
/// Return(s):	 (void) returns nothing
Tile& Tile::operator = ( const Tile& lhs )
{
	this->collision = lhs.collision;
	this->imageName = lhs.imageName;
	this->number = lhs.number;
	this->bin = lhs.bin;
	this->hex = BinaryConverter( lhs.bin ); 
	this->rect = lhs.rect;
	this->image = lhs.image;
	this->sprite = lhs.sprite;
	return *this;
}

/// Name:		 Destructor
/// Description: handles the destruction of this object
/// Param(s):	 none
/// Return(s):	 (void) returns nothing
Tile::~Tile()
{
}

/// Name:		 setImageName
/// Description: sets image name
/// Param(s):	 std::string
/// Return(s):	 (void) returns nothing
void Tile::setImageName( std::string imageName )
{
	this->imageName = imageName;
}

/// Name:		 setImageName
/// Description: sets image name and loads image and sprites
/// Param(s):	 std::string
/// Return(s):	 (void) returns nothing
void Tile::setImageNameAndLocation( std::string location )
{
	this->imageNameAndLocation = location;
	if( !this->image.LoadFromFile( location ) )
	{
		exit(1);
	}
	this->sprite.SetImage( this->image );
}

/// Name:		 setCollision
/// Description: sets the member variable collision
/// Param(s):	 none
/// Return(s):	 (void) returns nothing
void Tile::setCollision( bool collision)
{
	this->collision = collision;
	if( collision == true )
	{
		this->bin.at(COLLISION_BIT) = '1';
	}else
	{
		this->bin.at(COLLISION_BIT) = '0';
	}
	this->hex = BinaryConverter( this->bin );
}

/// Name:		 setNumber
/// Description: sets the member variable number
/// Param(s):	 none
/// Return(s):	 (void) returns nothing
void Tile::setNumber( unsigned int number )
{
	if( number > 255 )
	{
		std::cout << "error tile number out of range 0-255\n" << std::endl;
		exit(1);
	}
	this->number = number;

	/// convert the number into a binary string

	/************************************************************
	change the way you convert a integer to a binary so that
	there are less if else statements... use a loop with a
	variable that increments through 2 to the power of something
	************************************************************/
	std::string temp;
	int test = number;
	if( test == 0 )
	{
		temp = "00000000";
	}
	while( test != 0 )
	{
		if( test - 128 >= 0 )
		{
			temp.push_back( '1' );
			test -= 128;
		}
		else
		{
			temp.push_back( '0' );
		}

		if( test - 64 >= 0 )
		{
			temp.push_back( '1' );
			test -= 64;
		}
		else
		{
			temp.push_back( '0' );
		}

		if( test - 32 >= 0 )
		{
			temp.push_back( '1' );
			test -= 32;
		}
		else
		{
			temp.push_back( '0' );
		}

		if( test - 16 >= 0 )
		{
			temp.push_back( '1' );
			test -= 16;
		}
		else
		{
			temp.push_back( '0' );
		}

		if( test - 8 >= 0 )
		{
			temp.push_back( '1' );
			test -= 8;
		}
		else
		{
			temp.push_back( '0' );
		}

		if( test - 4 >= 0 )
		{
			temp.push_back( '1' );
			test -= 4;
		}
		else
		{
			temp.push_back( '0' );
		}

		if( test - 2 >= 0 )
		{
			temp.push_back( '1' );
			test -= 2;
		}
		else
		{
			temp.push_back( '0' );
		}

		if( test - 1 >= 0 )
		{
			temp.push_back( '1' );
			test -= 1;
		}
		else
		{
			temp.push_back( '0' );
		}
	}

	for( int i = 0; i < TILE_NUMBER_BIN_SIZE; i++ )
	{
		this->bin.at( i ) = temp.at( i );
	}
	this->hex = BinaryConverter( this->bin );
}

/// Name:		 setHex
/// Description: sets the hex string with the passed string
/// Param(s):	 std::string
/// Return(s):	 (void) returns nothing
void Tile::setHex(std::string hex)
{
	this->hex = hex;
}

/// Name:		 setBin
/// Description: sets the binary string with the passed string
/// Param(s):	 std::string
/// Return(s):	 (void) returns nothing
void Tile::setBin( std::string bin )
{
	this->bin = bin;
}

/// Name:		 setRect
/// Description: sets the rects top bottom left and right
///				 and the sprites top and left
/// Param(s):	 float top, float bottom, float left, float right
/// Return(s):	 (void) returns nothing
void Tile::setRect( float top, float bottom, float left, float right )
{
	this->rect.Top = top;
	this->rect.Bottom = bottom;
	this->rect.Left = left;
	this->rect.Right = right;
	sprite.SetX( left );
	sprite.SetY( top );
}

/// Name:		 getImageName
/// Description: gets the image name of this tile
/// Param(s):	 none
/// Return(s):	 (void) returns nothing
std::string Tile::getImageName()
{
	return this->imageName;
}

/// Name:		 getImageNameAndLocation
/// Description: gets the image name and locatoin of this tile
/// Param(s):	 none
/// Return(s):	 (void) returns nothing
std::string Tile::getImageNameAndLocation()
{
	return this->imageNameAndLocation;
}


/// Name:		 getCollision
/// Description: returns whether a Tile is collidable or not
/// Param(s):	 none
/// Return(s):	 bool collidable = true NON-collidable = false
bool Tile::getCollision()
{
	return this->collision;
}

/// Name:		 getNumber
/// Description: gets the tile number corrisponding to its position
///				 in the TileImageName vector.
/// Param(s):	 none
/// Return(s):	 unsigned int returns a number between 1-128
unsigned int Tile::getNumber()
{
	return this->number;
}

/// Name:		 getHex
/// Description: returns the hex string of this Tile
/// Param(s):	 none
/// Return(s):	 std::string returns the object's hex string
std::string Tile::getHex()
{
	return this->hex;
}

/// Name:		 getBin
/// Description: returns the binary string of this Tile
/// Param(s):	 none
/// Return(s):	 std::string returns the object's binary string
std::string Tile::getBin()
{
	return this->bin;
}

/// Name:		 getRect
/// Description: Returns the Tiles rect
/// Param(s):	 none
/// Return(s):	 sf::Rect<float>
sf::Rect<float> Tile::getRect()
{
	return this->rect;
}

sf::Image Tile::getImage()
{
	return this->image;
}

sf::Sprite Tile::getSprite()
{
	return this->sprite;
}